/*
 * Copyright 2018 The JA-SIG Collaborative. All rights reserved.
 * distributed with thi file and available online at
 */
package com.lap.codegen.dal.impl;

import com.lap.codegen.dal.DbDAO;
import com.lap.codegen.domain.Column;
import com.lap.codegen.domain.DbConf;
import com.lap.codegen.domain.Table;
import com.lap.codegen.exception.DbException;
import com.lap.codegen.utils.CodeUtils;
import com.lap.codegen.utils.TypeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.sql.*;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;

/**
 * <pre>
 *  MySQL数据操作对象
 * </pre>
 *
 * @author 劳水生 , 021(poker0325@me.com)
 * @version 1.0.0
 */
@Service("dbDAO")
public class MySQLDAO implements DbDAO {

    @Override
    public List<Table> queryGeneral(DbConf conf) throws DbException {
        List<Table> list = new LinkedList<>();
        try (Connection conn = DriverManager.getConnection(conf.getUrl(), conf.getUsername(), conf.getPassword()); PreparedStatement ps = conn.prepareStatement("SHOW TABLE STATUS "); ResultSet rs = ps.executeQuery();) {

            Table table = null;
            while (rs.next()) {
                String origName = rs.getString("Name");
                String comment = rs.getString("Comment");
                String newName = getNewName(conf, origName);
                table = new Table(origName, newName, comment);
                table.setUpperName(CodeUtils.getUpper(newName));
                table.setLowerName(CodeUtils.getLower(newName));
                table.setLineName(CodeUtils.getLine(newName));
                list.add(table);
                initColumn(conf, conn, table);
            }
        } catch (SQLException e) {
            throw new DbException(e);
        }
        return list;
    }

    /**
     * <pre>
     * 获取新表名
     * </pre>
     *
     * @param conf 配置信息
     * @param name 原始表名
     * @return
     */
    private String getNewName(DbConf conf, String name) {
        String prefix = conf.getPrefix();// 前缀
        String suffix = conf.getSuffix();// 后缀
        if (StringUtils.isNotBlank(prefix) && !name.equals(prefix) && name.startsWith(prefix)) {
            return name.substring(name.indexOf(prefix) + prefix.length());
        }
        if (StringUtils.isNotBlank(suffix) && !name.equals(suffix) && name.endsWith(suffix)) {
            return name.substring(0, name.indexOf(suffix));
        }
        return name;
    }

    /**
     * 对table的列进行赋值
     *
     * @param conf  配置
     * @param conn  连接池
     * @param table 表单
     * @throws SQLException
     */
    private void initColumn(DbConf conf, Connection conn, Table table) throws SQLException {
        try (PreparedStatement ps = conn.prepareStatement("SHOW FULL COLUMNS FROM " + table.getOrigName()); ResultSet rs = ps.executeQuery();) {

            List<Column> dataList = new LinkedList<>();
            table.setDataList(dataList);
            Column column = null;
            while (rs.next()) {
                String field = rs.getString("Field");
                if (StringUtils.isNotBlank(field)) {
                    column = new Column();
                    dataList.add(column);

                    column.setName(field);
                    column.setUpperName(CodeUtils.getUpper(field));
                    column.setLowerName(CodeUtils.getLower(field));

                    String type = rs.getString("Type");
                    column.setDbType(TypeUtils.getDbType(type));
                    String javaType = TypeUtils.getJavaType(type);
                    column.setJavaType(javaType);
                    column.setLength(TypeUtils.getLength(type));

                    String extra = rs.getString("Extra");
                    if ("auto_increment".equals(extra)) {
                        column.setAutoIncrement(true);
                    }

                    column.setComment(rs.getString("Comment"));
                    column.setMust(rs.getString("Null"));
                    String key = rs.getString("Key");
                    column.setKey(key);
                    if (Objects.nonNull(key) && "PRI".equals(key)) {
                        table.setPkType(javaType);
                        table.setPkName(CodeUtils.getUpper(field));
                    }
                    column.setWriteDomain(checkDomainWrite(field, conf));
                }
            }
        }
    }

    /**
     * 判断是否需要在domain中写入改字段,true=写，false=不写
     *
     * @param field 属性
     * @param conf  配置
     * @return
     */
    private boolean checkDomainWrite(String field, DbConf conf) {
        String[] array = conf.getExcludeField();
        if (Objects.isNull(array) || array.length == 0) {
            return true;
        } else {
            for (String str : array) {
                if (str.equalsIgnoreCase(field)) {
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    public List<Table> queryByTableName(DbConf conf, List<String> tableNames) throws DbException {
        List<Table> newList = new LinkedList<>();
        List<Table> list = queryGeneral(conf);
        if (list != null && !list.isEmpty()) {
            for (Table table : list) {
                if (validateTable(table.getName(), tableNames)) {
                    newList.add(table);
                }
            }
        }
        return newList;
    }

    /**
     * 判断表是否存在
     *
     * @param name       表名
     * @param tableNames 表名集合
     * @return
     */
    private boolean validateTable(String name, List<String> tableNames) {
        if (tableNames == null) {
            return false;
        } else if (tableNames.isEmpty()) {
            return true;
        } else {
            for (String str : tableNames) {
                if (StringUtils.isNotBlank(str) && str.equalsIgnoreCase(name)) {
                    return true;
                }
            }
        }
        return false;
    }

}
